package com.shengzhe.ostudent.common.filter;

import com.shengzhe.ostudent.common.exception.OsException;
import com.shengzhe.ostudent.utils.security.JwtUtils;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 虽说是拦截器，但是Servlet阶段并没有拦截器的概念，拦截器一般是一些高级Web框架提供的特性
 * 在本项目中，拦截器实际上是基于过滤器(Filter)进行实现
 */

// 拦截地址，拦截所有后台请求(即/admin这个路径为首的请求)，因为在本项目中，前台不需要登录也可以访问，所以只需要拦截后台
// (前台就是设计图中的那套供用户使用的界面，现在我们还没有实现到那部分)
@WebFilter("/admin/*")
public class AdminFilter implements Filter {
    // 排除后台接口中的login接口
    // 登录接口不能拦截，否则无法进行登录
    private final List<String> excludeUrls = new ArrayList<String>() {{
        add("/login");
    }};

    @Override
    public void init(FilterConfig filterConfig) {
        // 初始化阶段，没有什么需要在这里实现的功能
    }

    // 核心方法，请求到达我们的Controller层之前以及响应返回给客户端之前可以在这个方法进行对请求和响应的操作
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws ServletException, IOException {
        /**
         将通用ServletRequest对象强转为HttpServletRequest
         ServletRequest对象包含HTTP、FTP等任何类型的请求的方法，但是没有独属于某一种请求的方法
         本项目为Web项目，我们的请求也都是HTTP请求，所以这里直接强转为HttpServletRequest
         **/
        // admin接口均需鉴权
        HttpServletRequest request = (HttpServletRequest) req;
        // 放行排除列表中的请求, 排除列表就是上面那个保存着login路径的列表
        String pathInfo = request.getPathInfo();
        if (excludeUrls.contains(pathInfo)) {
            filterChain.doFilter(req, res);
            return;
        }
        // 不在排除名单中的请求开始进行鉴权拦截
        // 从请求头中获取token
        String token = request.getHeader("token");
        try {
            // 使用JWT工具类检查token, 如果token不通过会抛出异常，所以这里用try catch捕获异常
            JwtUtils.checkToken(token);
        } catch (OsException e) {
            // 抛出的异常就是我们的自定义异常OsException,
            // 这里我们把异常信息设置到Attribute, 目的是把异常信息传递给下一个拦截器
            req.setAttribute("ERR_ENUMS", e.getErrEnum());
        }
//        JwtUtils.checkToken(token);
        // 放行请求, 传递给下一个拦截器
        filterChain.doFilter(req, res);
    }

    @Override
    public void destroy() {
        // 拦截器销毁方法，这里也没有什么需要实现的功能
    }
}
